package com.bruce.tool.netty.socket.core;

import com.bruce.tool.common.exception.BaseRuntimeException;
import com.bruce.tool.common.util.LogUtils;
import com.bruce.tool.common.util.string.JsonUtils;
import com.bruce.tool.common.util.string.MapHandler;
import com.bruce.tool.netty.socket.constant.NettyErrorCode;
import com.bruce.tool.netty.socket.util.SocketUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Objects;

/**
 * @author bruce
 */
@Slf4j
@Sharable
public class SocketClientHandler extends ChannelInboundHandlerAdapter{

    private SocketClient client;

    private Integer reconnectCount = 0;

    public SocketClientHandler(SocketClient client) {
        this.client = client;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if( !( msg instanceof ByteBuf ) ){ return; }
        String originMessage = SocketUtils.transfer((ByteBuf) msg);
        Message clientMessage = JsonUtils.strToObj(originMessage,Message.class);
        if(Objects.isNull(clientMessage)){ return; }
        String message = clientMessage.getBody();
        if(message.contains(client.config().getPong())){
            LogUtils.info(log,"心跳检测,From:{},{}",JsonUtils.objToStr(clientMessage.getFrom()),message);
        }else{
            if(Objects.isNull(client.getListener()) ){
                throw new BaseRuntimeException(NettyErrorCode.NTERROR_CONFIG_NULL.getCode(),"监听器未初始化");
            }
            client.getListener().listen(message);
        }
    }

    @Override
    public void channelInactive(final ChannelHandlerContext ctx) {
        client.connect();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (!(evt instanceof IdleStateEvent)) {
            return;
        }
        if(reconnectCount >= 4){
            reconnectCount = 0;
            ctx.close();
            return;
        }
        reconnectCount++;
        IdleStateEvent e = (IdleStateEvent) evt;
        switch(e.state()){
            case READER_IDLE:
                reconnectCount ++;
                handleReaderIdle(ctx);
                break;
            case WRITER_IDLE:
                reconnectCount ++;
                handleWriterIdle(ctx);
                break;
            case ALL_IDLE:
                reconnectCount ++;
                handleAllIdle(ctx);
                break;
            default:
                break;
        }
    }

    /**状态为读闲置**/
    private void handleReaderIdle(ChannelHandlerContext ctx) {
        // do nothing
    }

    /**状态为写闲置**/
    private void handleWriterIdle(ChannelHandlerContext ctx) {
        Map body = MapHandler.build().add(client.config().getPing(),System.currentTimeMillis());
        String message = JsonUtils.objToStr(body);
        Message ping = Message.builder().from(client.getClientInfo()).body(message).build();
        ctx.writeAndFlush(Unpooled.copiedBuffer(JsonUtils.objToStr(ping).getBytes()));
    }

    /**读写均闲置**/
    private void handleAllIdle(ChannelHandlerContext ctx) {
        // do nothing
    }

}